
package com.apes.enquiry.supplier.jingshi.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.enquiry.supplier.jingshi.common.EpcOePjmc;
import com.apes.enquiry.supplier.jingshi.common.HttpUtils;
import com.apes.enquiry.supplier.jingshi.common.VinConstance;
import com.apes.enquiry.supplier.jingshi.model.EpcPartsList;
import com.apes.framework.api.DomainService;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.StringUtil;
import org.apache.commons.collections4.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Title: JingShiService
 * @Author fj
 * @Package com.apes.enquiry.supplier.jingshi.service
 * @Date 2023/6/7 16:10
 * @description: 精时接口封装
 */
@Service("jingShiService")
public class JingShiService extends DomainService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 精时3001接口
     * 根据VIN码查车型
     * @param request {"vin":"车架号","gonggaoNo":"公告号（非必填）"}
     * @return
     */
    public JSONObject queryByVin(SimpleRequest request){
        JSONObject jsonObject = request.getJO();
        String vin = jsonObject.getString("vinCode");
        String gonggaoNo = jsonObject.getString("gonggaoNo");
        //生成token
        String resource = null;
        if (ObjectUtils.isEmpty(gonggaoNo)){
            resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_CCX_TOKEN, vin);
        }else {
            resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_CCX_PARAM_TOKEN, vin, gonggaoNo);
        }
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        //构建完整请求
        String path = null;
        if (ObjectUtils.isEmpty(gonggaoNo)){
            path = String.format(VinConstance.VIN_CCX_PATH, vin, VinConstance.USER, token);
        }else {
            path = String.format(VinConstance.VIN_CCX_PATH_PARAM, vin, gonggaoNo, VinConstance.USER, token);
        }
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时4001接口
     * 通过oe号获取配件信息
     * @param request {"queryPartNumber":"搜索的oe号","queryMatchType":"搜索类型，exact为精准搜索，inexact为模糊搜索"}
     * @return
     */
    public JSONObject queryAccInfo(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        String queryPartNumber = requestJO.getString("queryPartNumber");
        String queryMatchType = requestJO.getString("queryMatchType");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_HQPJJCXX_TOKEN, queryPartNumber, queryMatchType);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_HQPJJCXX_PATH, queryPartNumber, queryMatchType, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时4004接口
     * 通过配件号(品牌件号/oe号)获取替换号码
     * @param request {"queryPartNumber":"OE配件号码","groupId":"品牌分组id"}
     * @return
     */
    public JSONObject queryReplaceCode(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        String partNumber = requestJO.getString("queryPartNumber");
        String groupId = requestJO.getString("groupId");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_HQTHHM_TOKEN, partNumber, groupId);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_HQTHHM_PATH, partNumber, groupId, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时4006接口
     * 获取OE对应的4S店价格
     * @param request {"partnumber":"搜索的oe号"}
     * @return
     */
    public JSONObject queryFspriceByOe(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String partnumber = requestJO.getString("partsCode");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_FSDJG_TOKEN, partnumber);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_FSDJG_PATH, partnumber, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5101接口
     * 一级目录
     * @param request {"epc":"品牌对应epc","vin":"车架号"}
     * @return
     */
    public JSONObject queryOneDirectory(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_YJML_TOKEN, epc, vin);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_YJML_PATH, epc, vin, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5102接口
     * 二级目录
     * @param request {"epc":"品牌对应epc","vin":"车架号","cata1Code":"上级目录，也就是一级目录返回字段中的cata_code值"}
     * @return
     */
    public JSONObject queryTwoDirectory(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        String cata1Code = requestJO.getString("cata1Code");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_EJML_TOKEN, epc, vin, cata1Code);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_EJML_PATH, epc, vin, cata1Code, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5103接口
     * 三级目录
     * @param request {"epc":"品牌对应epc","vin":"车架号","cata2Code":"上级目录的cata_code值，这里指二级类目接口返回的cata_code值"}
     * @return
     */
    public JSONObject queryThreeDirectory(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        String cata2Code = requestJO.getString("cata2Code");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_SJML_TOKEN, epc, vin, cata2Code);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_SJML_PATH, epc, vin, cata2Code, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5104接口
     * 四级目录
     * @param request {"epc":"品牌对应epc","vin":"车架号",
     *                "cata3Code":"上级目录的cata_code值，这里指三级类目接口返回的cata_code值"}
     * @return
     */
    public JSONObject queryFourDirectory(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        String cata3Code = requestJO.getString("cata3Code");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_FJML_TOKEN, epc, vin, cata3Code);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_FJML_PATH, epc, vin, cata3Code, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5105接口
     * 配件列表
     * @param request {"epc":"品牌对应epc","vin":"车架号","lastAataCode":"最后一级目录的cata_code值",
     *                "lastCataCodeLevel":"最后一级目录是几,根据请求类目的is_last节点判断最后一级是多少"}
     * @return
     */
    public JSONObject queryAccList(JSONObject request){
        String epc = request.getString("epc");
        String vin = request.getString("vinCode");
        String lastAataCode = request.getString("lastCataCode");
        String lastCataCodeLevel = request.getString("lastCataCodeLevel");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_PJLB_TOKEN,
                epc, vin, lastAataCode, lastCataCodeLevel);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_PJLB_PATH, epc, vin, lastAataCode, lastCataCodeLevel, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5106接口
     * 配件号码搜索
     * @param request {"epc":"品牌对应epc","vin":"车架号","queryMatchType":"搜索类型，
     *                exact为精准搜索，inexact为模糊搜索","queryPartNumber":"要搜索的oe号码"}
     * @return
     */
    public JSONObject queryByPartNumber(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        String queryMatchType = requestJO.getString("queryMatchType");
        String queryPartNumber = requestJO.getString("queryPartNumber");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_PJHMSS_TOKEN,
                epc, vin, queryMatchType, queryPartNumber);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_PJHMSS_PATH,
                epc, vin, queryMatchType, queryPartNumber, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5107接口
     * 配件EPC原厂名称搜索 {"epc":"品牌对应epc","vin":"车架号","queryMatchType":"搜索类型,exact为精准搜索,
     *                    inexact为模糊搜索","queryPartName":"要搜索的原厂配件名称"}
     * @param request
     * @return
     */
    public JSONObject queryEpcByName(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        String queryMatchType = requestJO.getString("queryMatchType");
        String queryPartName = requestJO.getString("queryPartName");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_PJEPCYCMCSS_TOKEN,
                epc, vin, queryMatchType, queryPartName);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_PJEPCYCMCSS_PATH,
                epc, vin, queryMatchType, queryPartName, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5108接口
     * 配件标准名称搜索
     * @param request {"epc":"品牌对应epc","vin":"车架号","queryMatchType":"搜索类型,exact为精准搜索,
     *                 inexact为模糊搜索","queryPartName":"要搜索的原厂配件名称"}
     * @return
     */
    public JSONObject queryAccByName(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        String queryMatchType = requestJO.getString("queryMatchType");
        String queryPartName = requestJO.getString("queryPartName");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_PJBZMCSS_TOKEN,
                epc, vin, queryMatchType, queryPartName);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        String path = String.format(VinConstance.VIN_PJBZMCSS_PATH,
                epc, vin, queryMatchType, queryPartName, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5109接口
     * 所有配件号码
     * @param request {"epc":"品牌对应epc","vin":"车架号"}
     * @return
     */
    public JSONObject queryAccCodeList(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_SYPJHM_TOKEN, epc, vin);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        //构建完整请求
        String path = String.format(VinConstance.VIN_SYPJHM_PATH, epc, vin, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5110接口
     * 所有epc配件名称
     * @param request {"epc":"品牌对应epc","vin":"车架号"}
     * @return
     */
    public JSONObject queryEpcAccList(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_SYEPCPY_TOKEN, epc, vin);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        //构建完整请求
        String path = String.format(VinConstance.VIN_SYEPCPY_PATH, epc, vin, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 精时5112接口
     * 配件搜索提示
     * @param request {"epc":"品牌对应epc","vin":"车架号","suggestKey":"搜索关键词，可以是数字、字母类型的配件号，或者配件名称"}
     * @return
     */
    public JSONObject queryAccPrompt(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        String epc = requestJO.getString("epc");
        String vin = requestJO.getString("vinCode");
        String suggestKey = requestJO.getString("suggestKey");
        //生成token
        String resource = String.format(VinConstance.TOKEN_BASE + VinConstance.VIN_PJSSTS_TOKEN, epc, vin, suggestKey);
        String token = DigestUtils.md5DigestAsHex((resource).getBytes());

        //构建完整请求
        String path = String.format(VinConstance.VIN_PJSSTS_PATH, epc, vin, suggestKey, VinConstance.USER, token);
        String result = HttpUtils.sendGet(path);
        return JSONObject.parseObject(result);
    }

    /**
     * 根据 vinCode 调用精时3001接口获取车型信息
     * @param request {"vin":"车架号"}
     * @return
     */
    public JSONObject queryCarTypeByVin(SimpleRequest request) {
        JSONObject result = new JSONObject();
        JSONObject vinInfo = queryByVin(request);

        JSONObject data = packingVinInfo(vinInfo);
        result.put("model",data);
        return result;
    }

    /**
     * 封装车型信息数据，以巴图鲁接口返回为基准
     * 仅补充前端使用到的字段
     * @param vinInfo
     * @return
     */
    private JSONObject packingVinInfo(JSONObject vinInfo){
        JSONObject info = new JSONObject();
        info.put("jingShiInfo",vinInfo);

        JSONObject sameCarType = new JSONObject();
        sameCarType.put("brandName",vinInfo.getString("brand"));
        info.put("sameCarType",sameCarType);
        return info;
    }

    private JSONObject getVinInfo(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        String result = (String) stringRedisTemplate.opsForHash().get("vinInfo", requestJO.getString("vinCode"));
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(result)){
            return JSONObject.parseObject(result);
        }
        JSONObject vinInfo = queryByVin(request);
        JSONObject data = vinInfo.getJSONObject("data");
        if (Objects.isNull(data)){
            throw new RuntimeException("您输入车牌号的VIN码有误，请核对后再输入~");
        }
        stringRedisTemplate.opsForHash().put("vinInfo",requestJO.getString("vinCode"), data.toJSONString());
        stringRedisTemplate.expire("vinInfo", 30 , TimeUnit.MINUTES);
        if (stringRedisTemplate.opsForHash().size("vinInfo") >= 1000){
            stringRedisTemplate.delete("vinInfo");
        }
        return data;
    }

    /**
     * 根据 vin 码和配件别名查询配件标准名称
     * @param request {"vinCode":"车架号（选填）", "keyword":"配件别名（必填）"}
     * @return
     */
    public JSONObject searchPartsHintsInfo(SimpleRequest request) {
        JSONObject requestJO = request.getJO();
        //得到车型epc
        JSONObject data = getVinInfo(request);
        if (!ObjectUtils.isEmpty(data)){
            String epc = data.getString("epc");
            requestJO.put("epc",epc);
            request.setData(requestJO);
        }
        JSONObject response = new JSONObject();
        //获取oe清单
        JSONObject oes = queryAccCodeList(request);
        oes.put("epc",requestJO.getString("epc"));
        if (!ObjectUtils.isEmpty(oes)){
            //得到精时oe清单与译码库匹配数据
            List<EpcOePjmc> normalList = handleOeData(oes);

            //与译码库匹配数据需再和epc版本库进行匹配，获取已有epc版本数据
            List<EpcOePjmc> epcOePjmcs = handleEpcData(normalList);

            //关键字查询若为oe号则为精准查询,反之则是模糊查询
            String keyword = requestJO.getString("keyword");
            List<EpcOePjmc> collect = epcOePjmcs.stream().filter(f -> keyword.equalsIgnoreCase(f.getPartnumber())).collect(Collectors.toList());
            List<EpcPartsList> epcPartsLists = new ArrayList<>();
            if (CollectionUtils.isEmpty(collect)){
                //oe号不存在的情况到俗称和标准配件名称库查询
                JSONArray categorys = requestJO.getJSONArray("categorys");
                if (Objects.isNull(categorys) || categorys.isEmpty()) {
                    categorys = this.invoke("master.category.findAllByClassifyNameOrName", MapUtil.mapper("data", MapUtil.mapper("keyword", keyword)));
                }
                if (!CollectionUtils.isEmpty(categorys)){
                    List<EpcPartsList> epcPartsList = handleNormalData(categorys, epcOePjmcs);
                    response.put("model",epcPartsList.size() > 10 ? epcPartsList.subList(0,10) : epcPartsList);
                    return response;
                }
            }else {
                for (EpcOePjmc epcOePjmc : collect) {
                    EpcPartsList epcPartsList = new EpcPartsList();
                    epcPartsList.setPartsCode(epcOePjmc.getPartnumber());
                    epcPartsList.setPartsAlias(epcOePjmc.getPartsAlias());
                    epcPartsList.setPartsName(epcOePjmc.getPjmc());
                    epcPartsLists.add(epcPartsList);
                }
                response.put("model",epcPartsLists);
                return response;
            }
        }
        if (!response.containsKey("model")){
            response.put("model", null);
        }
        return response;
    }

    /**
     * 处理封装oe清单数据
     * @param jsonObject
     * @return
     */
    private List<EpcOePjmc> handleOeData(JSONObject jsonObject){
        List<EpcOePjmc> pjmcArrayList = new ArrayList<>();
        String oes = jsonObject.getString("data");
        if (StringUtils.isEmpty(oes)){
            return pjmcArrayList;
        }
        String[] split = oes.split("@");

        //分批次 1000/批
        List<String> oeCodes = Arrays.asList(split);
        List<List<String>> partition = ListUtils.partition(oeCodes, 1000);

        List<EpcOePjmc> all = new ArrayList<>();
        partition.forEach(item -> {
            JSONObject result = JSON.parseObject(invoke("pj.EpcOePjmcService.queryByPartnumbers",
                    MapUtil.mapper("data", MapUtil.mapper("partnumbers", item, "EPC", jsonObject.getString("epc")))));
            JSONArray body = result.getJSONArray("body");
            String js = JSONObject.toJSONString(body);
            List<EpcOePjmc> epcOePjmcs = JSONObject.parseArray(js, EpcOePjmc.class);
            all.addAll(epcOePjmcs);
        });
        return all;
    }

    /**
     * 处理封装epc版本对应数据
     * @param list
     * @return
     */
    private List<EpcOePjmc> handleEpcData(List<EpcOePjmc> list) {
        //根据epc版本分组
        Map<String, List<EpcOePjmc>> groupEpcPj = list.stream().collect(Collectors.groupingBy(EpcOePjmc::getEpcBbmc));
        //与译码库匹配上的数据还需要和epc版本对照表进行对比，判断epc对照表是否存在该epc版本
        List<EpcOePjmc> epcOePjmcs = new ArrayList<>();
        groupEpcPj.forEach((k,v) -> {
            JSONObject result = JSONObject.parseObject(this.invoke("pj.EpcOePjmcService.queryByEpcBbmcCount",MapUtil.mapper("key", k)).toString());
            JSONArray body = result.getJSONArray("body");
            if (body.size() > 0) {
                epcOePjmcs.addAll(v);
            }
        });
        return epcOePjmcs;
    }

    /**
     * 处理俗称与标准名称匹配数据
     * @param categorys
     * @param all
     * @return
     */
    private List<EpcPartsList> handleNormalData(JSONArray categorys,List<EpcOePjmc> all){
        //根据名称匹配译码库对比出来的数据 `all`
        String categoryString = JSONObject.toJSONString(categorys);
        List<EpcPartsList> categories = JSONObject.parseArray(categoryString, EpcPartsList.class);

        //俗称结果与译码库结果进行匹配 获取交集
        List<EpcOePjmc> pjmcs = all.stream().filter(item -> categories.stream()
                .map(e -> {
                    if (! (Objects.equals(item.getPjmc(), e.getPartsName()) || Objects.equals(item.getPjmc(), e.getPartsAlias()))) {
                        return null;
                    } else {
                        item.setPartsAlias(e.getPartsAlias());
                        return item.getPjmc();
                    }
                }).collect(Collectors.toList())
                .contains(item.getPjmc()))
                .collect(Collectors.toList());

        List<EpcPartsList> epcPartsLists = new ArrayList<>();
        if (!CollectionUtils.isEmpty(pjmcs)){
            pjmcs.forEach(item -> {
                EpcPartsList epcPartsList = new EpcPartsList();
                if (pjmcs.stream().filter( EpcName -> item.getPjmc().equals(EpcName.getPjmc())).collect(Collectors.toList()).size() == 1) {
                    epcPartsList.setPartsCode(item.getPartnumber());
                }
                epcPartsList.setPartsAlias(item.getPartsAlias());
                epcPartsList.setPartsName(item.getPjmc());
                epcPartsLists.add(epcPartsList);
            });
        }
        return epcPartsLists;
    }

    /**
     * 根据oe号带出 配件4s店价格、图片
     * @param request {"vinCode":"LVHRM3854E5018890","partsNames":["气门室盖密封垫"],"partsCode":"000098713A"}
     * @return
     */
    public JSONObject queryPartsCodeInfo(SimpleRequest request) {
        JSONObject result = new JSONObject();

        JSONObject requestJO = request.getJO();
        //得到车型epc
        JSONObject vinInfo = queryByVin(request);
        JSONObject data = vinInfo.getJSONObject("data");
        if (!ObjectUtils.isEmpty(data)){
            String epc = data.getString("epc");
            requestJO.put("epc",epc);
            request.setData(requestJO);
        }
        String partsCode = requestJO.getString("partsCode");
        String keyword = requestJO.getJSONArray("partsNames").get(0).toString();//译码名称或者零件号
        if (StringUtils.isEmpty(partsCode)){
            //oe号或关键字精准查询,到译码库获取对应数据
            if (requestJO.getJSONArray("partsNames").size() == 1){
                //获取oe清单
                JSONObject jsonObject = queryAccCodeList(request);

                jsonObject.put("epc", requestJO.getString("epc"));
                //得到精时oe清单与译码库匹配数据
                List<EpcOePjmc> normalList = handleOeData(jsonObject);
                //与译码库匹配数据需再和epc版本库进行匹配，获取已有epc版本数据
                List<EpcOePjmc> epcOePjmcs = handleEpcData(normalList);

                List<EpcOePjmc> collect = normalList.stream().filter(f -> keyword.equalsIgnoreCase(f.getPartnumber())).collect(Collectors.toList());
                if (CollectionUtils.isEmpty(collect)){
                    //若搜索关键字存在中文括号需转为英文括号
                    String replace = keyword.replace("（", "(");
                    String rKeyword = replace.replace("）", ")");

                    //oe号获取不到则使用关键字到俗称与标准名称匹配
                    JSONArray categorys = requestJO.getJSONArray("categorys");
                    if (Objects.isNull(categorys) || categorys.isEmpty()) {
                        categorys = this.invoke("master.category.findNames", MapUtil.mapper("data", MapUtil.mapper("keyword", rKeyword)));
                    }
                    if (!CollectionUtils.isEmpty(categorys)){
                        List<EpcPartsList> epcPartsLists = handleNormalData(categorys, epcOePjmcs);
                        if (!CollectionUtils.isEmpty(epcPartsLists) && epcPartsLists.size() == 1){
                            requestJO.put("partsCode",epcPartsLists.get(0).getPartsCode());

                            JSONArray array = new JSONArray();
                            array.add(epcPartsLists.get(0).getPartsName());
                            requestJO.put("partsNames",array);
                        }
                    }
                }else {
                    EpcOePjmc epcOePjmc = collect.get(0);
                    requestJO.put("partsCode",epcOePjmc.getPartnumber());

                    JSONArray array = new JSONArray();
                    array.add(epcOePjmc.getPjmc());
                    requestJO.put("partsNames",array);
                }
            }
        }else {
            requestJO.put("partsCode", partsCode);
        }
        request.setData(requestJO);
        JSONObject fsprice = queryFspriceByOe(request);
        JSONArray datas = fsprice.getJSONArray("data");

        JSONArray resultArr = new JSONArray();
        JSONObject modelContent = packageData(requestJO, datas);
        if (keyword.equals(modelContent.getString("partsName")) || keyword.equals(modelContent.getString("partsCodes"))
                || ( requestJO.containsKey("partsCode") && requestJO.getString("partsCode").equals(modelContent.getString("partsCodes")) ) ){
            resultArr.add(modelContent);
        }
        result.put("model",resultArr);
        return result;
    }

    /**
     * 封装oe号、图片等数据返回
     * @param requestJO
     * @return
     */
    private JSONObject packageData(JSONObject requestJO,JSONArray data){
        JSONObject modelContent = new JSONObject();
        String partsCode = requestJO.getString("partsCode");

        modelContent.put("partsCodes",partsCode);
        if (requestJO.getJSONArray("partsNames").size() == 1){
            modelContent.put("partsName", requestJO.getJSONArray("partsNames").get(0));
            modelContent.put("standardName", requestJO.getJSONArray("partsNames").get(0));
        }

        //获取4s店最高价格
        JSONObject partsInfos = new JSONObject();
        if (!CollectionUtils.isEmpty(data)){
            List<JSONObject> objectList = data.toJavaList(JSONObject.class);
            OptionalDouble price = objectList.stream().mapToDouble(item -> Double.valueOf(item.getString("Price"))).max();
            partsInfos.put("price",price.getAsDouble());
            partsInfos.put("partsCode",partsCode);
        }

        //根据oe号获取配件基本信息
        SimpleRequest simpleRequest = new SimpleRequest();
        JSONObject jo = new JSONObject();
        jo.put("epc",requestJO.getString("epc"));
        jo.put("vinCode",requestJO.getString("vinCode"));
        jo.put("queryPartNumber",partsCode);
        jo.put("queryMatchType","exact");
        simpleRequest.setData(jo);
        JSONObject jsonObject = queryByPartNumber(simpleRequest);//精时5106接口
        if (!StringUtils.isEmpty(jsonObject.getJSONObject("data"))) {
            JSONObject searchlist = jsonObject.getJSONObject("data");
            JSONArray infos = searchlist.getJSONArray("searchlist");
            if (!CollectionUtils.isEmpty(infos)) {
                JSONArray epcPartsImages = new JSONArray();
                JSONArray pictures = new JSONArray();
                infos.toJavaList(JSONObject.class).forEach(item -> {
                    if (!StringUtils.isEmpty(item.getString("illustration_img_address"))) {
                        JSONObject epcPartsImage = new JSONObject();
                        epcPartsImage.put("imageCode", item.getString("illustration_img_address"));
                        epcPartsImage.put("imageUrl", String.format(VinConstance.IMAGE_URL, jo.getString("epc")) + item.getString("illustration_img_address"));

                        JSONObject picture = new JSONObject();
                        JSONObject imgCoordinate = queryAccList(new JSONObject(MapUtil.mapper("epc", requestJO.getString("epc"), "vinCode", requestJO.getString("vinCode"),
                                "lastCataCode", item.getString("cata_code"), "lastCataCodeLevel", item.getString("cata_level"))));
                        List list = disposePicture(imgCoordinate.getJSONObject("data"), item.getString("callout"));
                        String illustration_img_address = item.getString("illustration_img_address").replace("\\", "/");
                        picture.put("url", StringUtil.urlGetFile(String.format(VinConstance.IMAGE_URL, jo.getString("epc")) + illustration_img_address));
                        picture.put("points", list);
                        picture.put("filesName", illustration_img_address);
                        epcPartsImages.add(epcPartsImage);
                        pictures.add(picture);
                    }
                });
                partsInfos.put("pictures", pictures.toString());
                partsInfos.put("epcPartsImages", epcPartsImages);
            }
        }
        modelContent.put("partsInfos",partsInfos);
        return modelContent;
    }

    /**
     * 处理精时返回的图片，转换成我们自己的格式
     * @param data
     */
    public List disposePicture(JSONObject data, String callout){
        JSONArray all_img_hotspots = data.getJSONArray("all_img_hotspots");
        if (all_img_hotspots.isEmpty()) return null;

        JSONArray collects = new JSONArray();
        for (Object allImgHotspots: all_img_hotspots) {
            JSONObject allImgHotspotsO = (JSONObject) allImgHotspots;
            JSONObject imgHotspots = allImgHotspotsO.getJSONObject("img_hotspots");
            if (imgHotspots.isEmpty()) continue;
            JSONArray hotspots = imgHotspots.getJSONArray("hotspots");
            if (hotspots == null || hotspots.isEmpty()) continue;
            JSONArray callouts = hotspots.toJavaList(JSONObject.class)
                    .stream().filter(item -> {
                        String itemCallout = item.getString("callout");
                        if (!Arith.isNumeric(callout) || !Arith.isNumeric(itemCallout)) {
                            return callout.equals(itemCallout);
                        } else {
                            if (itemCallout.length() > 8) { // 超过 8 位超过Integer最大值
                                return callout.equals(itemCallout);
                            }
                            // 存在数据，callout = “04”， item.getInteger("callout") = 4，先转换后比较
                            return Integer.valueOf(callout).equals(item.getInteger("callout"));
                        }
                    }).collect(Collectors.toCollection(JSONArray::new));
            collects.addAll(callouts);
            if (!collects.isEmpty()) break;
        }


        List list = new ArrayList<>();
        collects.toJavaList(JSONObject.class).forEach(item ->{
            //我们平台的图片坐标
            JSONObject points = new JSONObject();
            points.put("x", item.getInteger("topleft_x"));
            points.put("y", item.getInteger("topleft_y"));
            points.put("h", 20);
            points.put("w", callout.length()*10);
            points.put("sn", item.getString("callout"));
            list.add(points);
        });

        return list;
    }

    /**
     * 替换编码接口
     * @param request
     * @return
     */
    public JSONObject queryPartsReplaceCode(SimpleRequest request){
        JSONObject requestJO = request.getJO();
        requestJO.put("queryMatchType","exact");
        request.setData(requestJO);
        //获取配件group_id
        JSONObject accInfo = queryAccInfo(request);
        JSONArray infos = accInfo.getJSONArray("data");

        JSONObject data = new JSONObject();
        if (!CollectionUtils.isEmpty(infos)){
            JSONObject info = (JSONObject) infos.get(0);
            String groupId = info.getString("Group_id");
            requestJO.put("groupId",groupId);
            request.setData(requestJO);
            JSONObject replaceCode = queryReplaceCode(request);
            data = replaceCode.getJSONObject("data");
        }
        return data;
    }
}
